<?php
declare (strict_types = 1);

namespace app;

use think\App;
use think\exception\ValidateException;
use think\Response;
use think\Validate;

use app\common\service\JwtService;

/**
 * 控制器基础类
 */
abstract class BaseController
{
    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * JWT服务实例
     * @var JwtService
     */
    protected $jwtService;

    /**
     * 当前用户信息
     * @var array
     */
    protected $userInfo = [];

    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {
        $this->app     = $app;
        $this->request = $this->app->request;
        $this->jwtService = new JwtService();

        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {
        // 默认进行JWT验证，可在子类中重写此方法并移除验证
        $this->verifyToken();
    }

    public function getUserInfo(){
        if (empty($this->userInfo)) {
            $this->error('无法找到用户信息');
        }
        return $this->userInfo;
    }
    /**
     * 验证JWT Token
     * @return void
     */
    protected function verifyToken()
    {
        // 获取当前请求的方法名
        $rule = $this->request->rule();
        $ruleName = $rule->getName();
        $functionArray = explode('@',$ruleName);

        // 检查是否在跳过验证的方法列表中
        $skipMethods = $this->skipAuthMethods();
        if (isset($functionArray[1]) && in_array($functionArray[1], $skipMethods)) {
            return;
        }

        // 从header中获取Authorization
        $token = $this->request->header('auth');

        // 检查token格式
        if (empty($token)) {
            $this->errorResponse('没找到有效认证令牌', 401);
        }


        // 验证token
        $payload = $this->jwtService->validateToken($token);

        if (!$payload) {
            $this->errorResponse('无效的认证令牌', 401);
        }

        // 保存用户信息
        $this->userInfo = [
            'uid' => $payload['iss'],
            'user_name' => $payload['aud']
        ];
    }

    /**
     * 允许跳过JWT验证的方法
     * 子类可以重写此方法以指定不需要验证的方法
     * @return array
     */
    protected function skipAuthMethods(): array
    {
        return [];
    }

    /**
     * 验证数据
     * @access protected
     * @param  array        $data     数据
     * @param  string|array $validate 验证器名或者验证规则数组
     * @param  array        $message  提示信息
     * @param  bool         $batch    是否批量验证
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, $validate, array $message = [], bool $batch = false)
    {
        try {
            if (is_array($validate)) {
                $v = new Validate();
                $v->rule($validate);
            } else {
                if (strpos($validate, '.')) {
                    // 支持场景
                    [$validate, $scene] = explode('.', $validate);
                }
                $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
                $v     = new $class();
                if (!empty($scene)) {
                    $v->scene($scene);
                }
            }

            $v->message($message);

            // 是否批量验证
            if ($batch || $this->batchValidate) {
                $v->batch(true);
            }

            return $v->failException(true)->check($data);
        }catch (\Exception $e){
            return $e->getMessage();
        }

    }

    /**
     * 成功响应
     * @param array $data 数据
     * @param string $msg 消息
     * @param int $code 状态码
     * @return Response
     */
    protected function success($data = [], $msg = 'success', $code = 200)
    {
        return Response::create([
            'code' => $code,
            'msg' => $msg,
            'data' => $data
        ], 'json');
    }

    /**
     * 错误响应
     * @param string $msg 错误消息
     * @param int $code 状态码
     */
    protected function error($msg = 'error', $code = 400): Response
    {
       return Response::create([
            'code' => $code,
            'msg' => $msg,
            'data' => []
        ], 'json', $code);

    }

    protected function errorResponse($msg = 'error', $code = 400)
    {
        Response::create([
            'code' => $code,
            'msg' => $msg,
            'data' => []
        ], 'json', $code)->send();
        exit;
    }
}
